package com.wuhao.code.check.model

import com.aegis.mybatis.xmlless.annotations.*
import com.aegis.mybatis.xmlless.constant.ClassNames
import com.aegis.mybatis.xmlless.enums.TestType
import com.aegis.mybatis.xmlless.model.ChooseCriteriaInfo
import com.aegis.mybatis.xmlless.model.JoinObjectInfo
import com.aegis.mybatis.xmlless.model.base.BaseClassWrapper
import com.intellij.psi.PsiPrimitiveType
import com.intellij.psi.PsiVariable
import com.wuhao.code.check.*
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
import org.jetbrains.kotlin.psi.KtAnnotationEntry

/**
 *
 * @author 吴昊
 * @date 2024/1/19 22:38
 * @since v0.0.0
 * @version 1.0
 */
abstract class BaseJavaPsiElementWrapper(el: PsiVariable) : BasePsiAnnotatedElementWrapper<PsiVariable>(el) {

  override fun getType(): BaseClassWrapper {
    val typeClass = element.getTypeClass()
    if (typeClass != null) {
      return PsiClassWrapper(typeClass)
    }
    error("无法识别${element}的类型")
  }

  override fun getChooseCriteria(): ChooseCriteriaInfo {
    return createChooseFromWhenList() ?: ChooseCriteriaInfo(
        element.annotations.filter {
          it.hasQualifiedName(TestCriteria::class.java.name)
        }.map {
          val test = it.getAttributeValue(TestCriteria::ifExpression.name)!!.toStringValue()
          val sql = it.getAttributeValue(TestCriteria::sqlExpression.name)!!.toStringValue()
          TestCriteria(test, sql)
        }, ""
    )
  }

  override fun getJoinPropertyList(): List<JoinObjectInfo> {
    if (!element.hasAnnotation(FeignProperty::class.java.name)) {
      return listOf()
    }
    return element.annotations.filter {
      it.hasQualifiedName(FeignProperty::class.java.name)
    }.map {
      if (it is KtLightAnnotationForSourceEntry) {
        resolveJoinObjectFromKtAnnotation(it.kotlinOrigin as KtAnnotationEntry)
      } else {
        var joinOnTargetProperty = ""
        var joinOnThisProperty = ""
        var alias = ""
        lateinit var targetClassWrapper: BaseClassWrapper

        it.attributes.forEach { attribute ->
          when (attribute.attributeName) {
            FeignProperty::joinOnTargetProperty.name ->
              joinOnTargetProperty = attribute.attributeValue?.toStringValue() ?: ""

            FeignProperty::joinOnThisProperty.name   ->
              joinOnThisProperty = attribute.attributeValue?.toStringValue() ?: ""

            FeignProperty::alias.name                -> alias = attribute.attributeValue?.toStringValue() ?: ""
            FeignProperty::targetEntity.name         -> {
              val psiClass = resolvePsiClass(attribute.attributeValue) ?: error(
                  "无法解析 %s 字段上的 %s 注解的 %s 属性".format(
                      element.name, FeignProperty::class.java.simpleName, attribute.attributeName
                  )
              )
              targetClassWrapper = PsiClassWrapper(psiClass)
            }
          }
        }
        JoinObjectInfo(joinOnTargetProperty, joinOnThisProperty, alias, targetClassWrapper)
      }
    }
  }

  override fun getTypeHandlerName(): String? {
    val anno = this.element.getAnnotation(Handler::class.java.name) ?: return null
    val value = anno.getAttributeValue("value")
    val psiClass = resolvePsiClass(value)
    if (psiClass != null) {
      return psiClass.qualifiedName
    }
    if (element.hasAnnotation(JsonMappingProperty::class.java)) {
      return "com.aegis.mybatis.xmlless.handler.JsonTypeHandler"
    }
    return null
  }

  override fun getParameterTestTypeList(): List<TestType> {
    return element.getStringListAnnotationValue(Test::class.java.name).map {
      TestType.valueOf(it)
    }
  }

  override fun isPrimitive(): Boolean {
    return element.type is PsiPrimitiveType
  }

  override fun isString(): Boolean {
    return element.getTypeClass()?.qualifiedName == "java.lang.String"
  }

  override fun isCollection(): Boolean {
    val typeClass = this.element.getTypeClass()
    if (typeClass != null) {
      val allSuperClasses = typeClass.getAllSuperClassNames()
      return allSuperClasses.contains(ClassNames.JAVA_COLLECTION)
    }
    return false
  }

}
